package it.lovaex.scb.unittests;

import static org.junit.Assert.assertEquals;
import it.lovaex.scb.Cart.Cart;
import it.lovaex.scb.factory.IDiscountRateFactory;
import it.lovaex.scb.model.BookItem;
import it.lovaex.scb.model.GroceryItem;
import it.lovaex.scb.model.Item;

import java.math.BigDecimal;

import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;

public class CartTest {

	private Cart sut;
	private IDiscountRateFactory discountFactory;
	
	@Before
	public void SetUp(){
		discountFactory = EasyMock.createNiceMock(IDiscountRateFactory.class);
		sut = new Cart(discountFactory);
	}
	
	@Test
	public void test_add_remove() {
		sut.add(0, new Item("itemDescription", BigDecimal.valueOf(0)));
		assertEquals(sut.isEmpty(), false);
		sut.empty();
		assertEquals(sut.isEmpty(), true);
	}
	
	@Test
	public void test_getFinalTotal_with_no_discount() {
		EasyMock.expect(discountFactory.getByItemCode("NotDiscountedItem")).andReturn(BigDecimal.ZERO).times(2);
		EasyMock.expect(discountFactory.getByTotal(BigDecimal.valueOf(12))).andReturn(BigDecimal.ZERO).once();
		EasyMock.replay(discountFactory);
		
		sut.add(2, new Item("itemDescription", BigDecimal.valueOf(1)));
		sut.add(2, new Item("itemDescription", BigDecimal.valueOf(5)));
		assertEquals(sut.isEmpty(), false);

		BigDecimal expected = BigDecimal.valueOf(1*2 + 2*5);
		assertEquals(expected, sut.getFinalTotal());
	}
	
	@Test
	public void test_getFinalTotal_with_item_discount() {
		EasyMock.expect(discountFactory.getByItemCode("NotDiscountedItem")).andReturn(BigDecimal.valueOf(0.1)).times(2);
		EasyMock.expect(discountFactory.getByTotal(BigDecimal.valueOf(1*2*(1-0.1) + 2*5*(1-0.1)))).andReturn(BigDecimal.ZERO).once();
		EasyMock.replay(discountFactory);
		
		sut.add(2, new Item("itemDescription", BigDecimal.valueOf(1)));
		sut.add(2, new Item("itemDescription", BigDecimal.valueOf(5)));
		assertEquals(sut.isEmpty(), false);

		BigDecimal expected = BigDecimal.valueOf(1*2*(1-0.1) + 2*5*(1-0.1));
		assertEquals(expected, sut.getFinalTotal());
	}
	
	@Test
	public void test_getFinalTotal_with_different_item_discount() {
		EasyMock.expect(discountFactory.getByItemCode("Grocery")).andReturn(BigDecimal.valueOf(0.1)).once();
		EasyMock.expect(discountFactory.getByItemCode("Book")).andReturn(BigDecimal.valueOf(0.2)).once();
		EasyMock.expect(discountFactory.getByTotal(BigDecimal.valueOf(1*2*(1-0.1) + 2*5*(1-0.2)))).andReturn(BigDecimal.ZERO).once();
		EasyMock.replay(discountFactory);
		
		sut.add(2, new GroceryItem("itemDescription", BigDecimal.valueOf(1)));
		sut.add(2, new BookItem("itemDescription", BigDecimal.valueOf(5)));
		assertEquals(sut.isEmpty(), false);

		BigDecimal expected = BigDecimal.valueOf(1*2*(1-0.1) + 2*5*(1-0.2));
		assertEquals(expected, sut.getFinalTotal());
	}
	
	@Test
	public void test_getFinalTotal_with_final_discount() {
		EasyMock.expect(discountFactory.getByItemCode("NotDiscountedItem")).andReturn(BigDecimal.ZERO).times(2);
		EasyMock.expect(discountFactory.getByTotal(BigDecimal.valueOf(1*2 + 2*5))).andReturn(BigDecimal.valueOf(0.1)).once();
		EasyMock.replay(discountFactory);
		
		sut.add(2, new Item("itemDescription", BigDecimal.valueOf(1)));
		sut.add(2, new Item("itemDescription", BigDecimal.valueOf(5)));
		assertEquals(sut.isEmpty(), false);

		BigDecimal expected = BigDecimal.valueOf((1*2 + 2*5)*(1-0.1));
		assertEquals(expected, sut.getFinalTotal());
	}
	
	@Test
	public void test_getFinalTotal_with_final_discount_and_different_item_discounts() {
		EasyMock.expect(discountFactory.getByItemCode("Grocery")).andReturn(BigDecimal.valueOf(0.1)).once();
		EasyMock.expect(discountFactory.getByItemCode("Book")).andReturn(BigDecimal.valueOf(0.2)).once();
		EasyMock.expect(discountFactory.getByTotal(BigDecimal.valueOf((1*2)*(1-0.1) + (2*5)*(1-0.2)))).andReturn(BigDecimal.valueOf(0.1)).once();
		EasyMock.replay(discountFactory);
		
		sut.add(2, new GroceryItem("itemDescription", BigDecimal.valueOf(1)));
		sut.add(2, new BookItem("itemDescription", BigDecimal.valueOf(5)));
		assertEquals(sut.isEmpty(), false);

		BigDecimal expected = BigDecimal.valueOf(((1*2)*(1-0.1) + (2*5)*(1-0.2))*(1-0.1));
		assertEquals(expected, sut.getFinalTotal());
	}
}
